﻿using System.ComponentModel;
using System.Windows.Controls;
using Trinity.Components.Combat;
using Trinity.Components.Combat.Resources;
using Trinity.Framework.Actors.ActorTypes;
using Trinity.Framework.Helpers;
using Trinity.Framework.Objects;
using Trinity.Framework.Reference;
using Trinity.UI;
using Zeta.Common;
using Zeta.Game.Internals.Actors;
using System.Collections.Generic;
using Trinity.Framework;


namespace Trinity.Routines.Necromancer
{
    public sealed class NecromancerGraceOfInarius : NecroMancerBase, IRoutine
    {
        #region Definition

        public string DisplayName => "伊纳瑞斯套装\\骨套\\圣套";
        public string Description => "伊纳瑞斯套装\\骨套\\圣套 - 最好带团结 - 装备技能抄天梯，把全能换团结";
        public string Author => "SY";
        public string Version => "7.3";
        public string Url => "小怪数设为10左右（不打小怪没尸体）,务必忽略霸王（Juggernaut）并开启自带躲避";
        public Build BuildRequirements => new Build
            {
            Sets = new Dictionary<Set, SetBonus>
            {
                { Sets.GraceOfInarius, SetBonus.Third },
            },
            Skills = new Dictionary<Skill, Rune>
            {
                { Skills.Necromancer.CorpseLance, null },
                { Skills.Necromancer.GrimScythe, null },
            },
            };
        
        #endregion

        public TrinityPower GetOffensivePower()
        {
            TrinityPower power;
            TrinityActor target;

           

            if (TryDecrepifyPower(out power))
                return power;
                
            if (TryBloodRushPower(out power))
                return power;

            if (ShouldBoneArmor() && !Skills.Necromancer.BoneArmor.IsBuffActive )
                return BoneArmor();

             if ((ShouldApplyCurseWithScythe() || Core.Player.CurrentHealthPct < 0.5) && ShouldGrimScythe(out target))
                return GrimScythe(target);

            if (TryCorpseLancePower(out power))
                return power;
            
            if (TryLandOfTheDeadPower(out power))
                return power;

            if (TrySecondaryPower(out power))
                return power;

            if (TryPrimaryPower(out power))
                return power;

            return null;
        }

        protected bool TryBloodRushPower(out TrinityPower power)
            {
            TrinityActor target;
            Vector3 position;
            power = null;

            if (ShouldBloodRush(out position))
                {
                power = BloodRush(position);
                }

            return power != null;
            }
        protected bool TryDecrepifyPower(out TrinityPower power)
            {
            TrinityActor target;
            Vector3 position;
            power = null;

            if (ShouldDecrepify(out target) && (Core.Player.PrimaryResourcePct > 0.9) && (TargetUtil.AnyMobsInRange(60f, 4) || !TargetUtil.AnyBossesInRange(60f)))
                {
                power = Decrepify(target);
                }
            return power != null;
            }
        protected bool TryCorpseLancePower(out TrinityPower power)
            {
            TrinityActor target;
            Vector3 position;
            power = null;

            if (ShouldCorpseLance(out target))
                {
                power = CorpseLance(target);
                }
            return power != null;
            }
        protected bool TryLandOfTheDeadPower(out TrinityPower power)
            {
            TrinityActor target;
            Vector3 position;
            power = null;
            if (ShouldLandOfTheDead(out target))
                {
                power = LandOfTheDead();
                }
            return power != null;
            }
        protected override bool ShouldGrimScythe(out TrinityActor target)
            {
            target = null;

            if (!Skills.Necromancer.GrimScythe.CanCast())
                return false;
            
             target = TargetUtil.GetBestClusterUnit() ?? CurrentTarget;

            return target != null;
            }

        protected override bool ShouldBloodRush(out Vector3 position)
            {
            position = Vector3.Zero;

            if (!Skills.Necromancer.BloodRush.CanCast())
                return false;
            if(Core.Player.CurrentHealthPct < 0.6 && Skills.Necromancer.BloodRush.CurrentRune == Runes.Necromancer.Potency)
                {
                position = TargetUtil.GetSafeSpotPosition(50f);
                return position != Vector3.Zero;
                }
			
            if (Skills.Necromancer.BloodRush.CooldownRemaining > 0)
                return false;

            position = TargetUtil.GetBestClusterPoint();

            if (Skills.Necromancer.BloodRush.CurrentRune == Runes.Necromancer.Metabolism && (Core.Player.Position.Distance(position) < 40f || Core.Player.CurrentHealthPct < 0.5))
                return false;

            return position != Vector3.Zero;
            }

        protected override bool ShouldCorpseLance(out TrinityActor target)
            {
            target = CurrentTarget;
            if (!Skills.Necromancer.CorpseLance.CanCast())
                return false;

            /*if(Skills.Necromancer.LandOfTheDead.IsBuffActive)
                {
                    target = TargetUtil.BestEliteInRange(15f, true);
                    target = target == null ? TargetUtil.ClosestUnit(15f) ?? null : target;
                    return target != null;
                }*/
            if(TargetUtil.CorpseCount(80f) > 0 || Skills.Necromancer.LandOfTheDead.IsBuffActive)
               {
                   return true;
               }
                return false;

            }

         protected override bool ShouldLandOfTheDead(out TrinityActor target)
            {
               target = CurrentTarget;
              if (!Skills.Necromancer.LandOfTheDead.CanCast())
                return false;

            if ( CurrentTarget.IsBoss || CurrentTarget.IsElite || TargetUtil.AnyElitesInRange(10f, 1))
                {
                    return true;
                }
                return false;
            }


        protected override bool ShouldDecrepify(out TrinityActor target)
            {
            target = null;
            if (!Skills.Necromancer.Decrepify.CanCast())
                return false;

            if (Player.PrimaryResource < PrimaryEnergyReserve)
                return false;

            // todo: investigate why cant find the power on monsters.         

            // anti-spam workaround
            if (Skills.Necromancer.Decrepify.TimeSinceUse < 2000)
                return false;

            target = TargetUtil.BestTargetWithoutDebuff(70f, SNOPower.P6_Necro_Decrepify);
            return target != null;
            }

        protected override bool ShouldBoneArmor()
            {
            if (!Skills.Necromancer.BoneArmor.CanCast())
                return false;

            if (!TargetUtil.AnyMobsInRange(15f))
                return false;

            // todo Need a way to check the cooldown properly, PowerManager/CanCast doesnt seem to be catching it.
            if (Skills.Necromancer.BoneArmor.TimeSinceUse < 10000)
                return false;

            // Inarius Set inceases damage making it more useful than just for defence
            // Wisdom of Kalan ring increases stacks by 5

            //if (Core.Buffs.GetBuff(SNOPower.P6_Necro_BoneArmor)?.Remaining.TotalSeconds > 0)
            //    return false;

            return true;
            }


        private bool ShouldApplyCurseWithScythe()
        {
            // Inarius build with Shadowhook should rarely run out of resource to force primary,
            // so it needs to be occasionally prioritized to apply curses.
            return Runes.Necromancer.CursedScythe.IsActive && Skills.Necromancer.GrimScythe.TimeSinceUse > 2000;
        }

        protected override bool ShouldCommandSkeletons(out TrinityActor target)
        {
            if (base.ShouldCommandSkeletons(out target))
            {
                return Skills.Necromancer.CommandSkeletons.TimeSinceUse > 5000;
            }
            return false;
        }

        public TrinityPower GetDefensivePower()
        {
            return GetBuffPower();
        }

        public TrinityPower GetBuffPower()
        {
            if (Player.CurrentHealthPct < 0.25 && Skills.Necromancer.BloodRush.CanCast())
            {
                return BloodRush(Avoider.SafeSpot);
            }
            // Put up bone armor when running around with high cluster size setting and not yet fighting
            if (ShouldBoneArmor())
                {
                return BoneArmor();
                }
            return null;
        }

        public TrinityPower GetDestructiblePower()
        {
            return DefaultDestructiblePower();
        }

        public TrinityPower GetMovementPower(Vector3 destination)
        {
            TrinityPower power;

            if (!IsInCombat || CurrentTarget != null && CurrentTarget.IsElite && CurrentTarget.Position.Distance(destination) <= 10f)
            {
                if (TryBloodrushMovement(destination, out power))
                    return power;
            }

            /*TrinityActor target;
            if (Skills.Necromancer.Decrepify.CanCast() && (Core.Player.PrimaryResourcePct > 0.9) && (TargetUtil.AnyMobsInRange(60f, 4) || !TargetUtil.AnyBossesInRange(60f)))
                {
                target = TargetUtil.ClosestUnit(50f);
                if (target != null)
                    {
                    return Decrepify(target);
                    }
                }
            if (ShouldBoneArmor())
                {
                return BoneArmor();
                }

            /*if (TargetUtil.AnyMobsInRange(10f) && Skills.Necromancer.GrimScythe.CanCast())
                {
                target = TargetUtil.ClosestUnit(10f);
                if (target != null)
                    {
                    return GrimScythe(TargetUtil.ClosestUnit(10f));
                    }
                }*/
            return Walk(destination);
        }



        #region Settings      

        public override int ClusterSize => Settings.ClusterSize;
        public override float EmergencyHealthPct => Settings.EmergencyHealthPct;

        IDynamicSetting IRoutine.RoutineSettings => Settings;
        public NecromancerGraceOfInariusSettings Settings { get; } = new NecromancerGraceOfInariusSettings();

        public sealed class NecromancerGraceOfInariusSettings : NotifyBase, IDynamicSetting
        {
            //private SkillSettings _wrathOfTheBerserker;
            //private SkillSettings _furiousCharge;

            private int _clusterSize;
            private float _emergencyHealthPct;

            [DefaultValue(1)]
            public int ClusterSize
            {
                get { return _clusterSize; }
                set { SetField(ref _clusterSize, value); }
            }

            [DefaultValue(0.4f)]
            public float EmergencyHealthPct
            {
                get { return _emergencyHealthPct; }
                set { SetField(ref _emergencyHealthPct, value); }
            }

            //public SkillSettings WrathOfTheBerserker
            //{
            //    get { return _wrathOfTheBerserker; }
            //    set { SetField(ref _wrathOfTheBerserker, value); }
            //}

            //public SkillSettings FuriousCharge
            //{
            //    get { return _furiousCharge; }
            //    set { SetField(ref _furiousCharge, value); }
            //}

            //#region Skill Defaults

            //private static readonly SkillSettings WrathOfTheBerserkerDefaults = new SkillSettings
            //{
            //    UseMode = UseTime.Selective,
            //    Reasons = UseReasons.Elites | UseReasons.HealthEmergency
            //};

            //private static readonly SkillSettings FuriousChargeDefaults = new SkillSettings
            //{
            //    UseMode = UseTime.Default,
            //    RecastDelayMs = 200,
            //    Reasons = UseReasons.Blocked
            //};

            //#endregion

            public override void LoadDefaults()
            {
                base.LoadDefaults();
                //WrathOfTheBerserker = WrathOfTheBerserkerDefaults.Clone();
                //FuriousCharge = FuriousChargeDefaults.Clone();
            }

            #region IDynamicSetting

            public string GetName() => GetType().Name;
            public UserControl GetControl() => UILoader.LoadXamlByFileName<UserControl>(GetName() + ".xaml");
            public object GetDataContext() => this;
            public string GetCode() => JsonSerializer.Serialize(this);
            public void ApplyCode(string code) => JsonSerializer.Deserialize(code, this, true);
            public void Reset() => LoadDefaults();
            public void Save() { }

            #endregion
        }

        #endregion


    }
}


